function WriteJsonSources(registrySourcesUrl, returnUrl) {// create an object to write
	// json das sources from the
	// registry

	this.registrySourcesUrl = registrySourcesUrl;
	this.returnUrl=returnUrl;// || window.location.href.substring(0, window.location.href.indexOf("sources")+7);//chop off any queryparams et
	
	var sourceUtils=new SourceUtils();
	this.html = "";// intialize and emptuy var for writing html to associated
	// with this object
	this.tableHeadHtml = tableHeadHtml;
	this.writeSources = writeSource;
	this.writeRows = writeRows;
	this.writeNavigationText = writeNavigationText;
	this.writeTableEnd = writeTableEnd;
	this.getSourcesTable = getSourcesTable;
	this.getRegistryUrlFromPath = getRegistryUrlFromPath;
	this.createPropertyMap = createPropertyMap;
	this.getQueryFromFullPath=getQueryFromFullPath;
	this.getNewQueryUrl=getNewQueryUrl;
	var showNumberOfCaps = 13;
	var itemsPerPage = 100;
	var start = 1;
	var stop = 10;
	var totalSources = 40;

	var caps = new Array();
	caps[0] = "sources";
	caps[1] = "stylesheet";
	caps[2] = "features";
	caps[3] = "types";
	caps[4] = "sequence";
	caps[5] = "entry_points";
	caps[6] = "alignment";
	caps[7] = "structure";
	caps[8] = "interaction";
	caps[9] = "bigfile-bam";
	caps[10] = "bigfile-bigbed";
	caps[11] = "bigfile-bigwig";
	caps[12] = "adjacent-feature";
	caps[13] = "format";
	caps[14] = "unknown-segment";
	caps[15] = "unknown-feature";
	caps[16] = "error-segment";
	caps[17] = "maxbins";
	caps[18] = "cors";
	caps[19] = "feature-by-id";
	caps[20] = "adjacent-feature";
	
	function getNewQueryUrl(){
		var currentQuery=window.location.href;
		//if sort is already in the url we need to replace it not add it, check for reverse also.
		if(currentQuery.indexOf("sort=")>0){
			//hopefully sort has been added on the end by the reg interface so lets just chop it off
			var index=currentQuery.indexOf("sort")
			currentQuery=currentQuery.substring(0, index);
		}
			
		if(currentQuery.indexOf("?")>0){
			if(currentQuery.indexOf(';')>0)return currentQuery;
			return currentQuery+';';//add a param seperator if non exists on the end
		}
		return currentQuery+'?';//no ? already so add one
	}
	

	function tableHeadHtml() {
		this.html = "";
		html = '';// reset the data
		html += '<div id=\"table\"><table id=\"list\"class=\"dastable\">';
		// print headers

		html += '<tr class="row0">';

		html += '<td><b>pos</pos></td>';
		html += '<td><b>ID<b><a href="'+this.getNewQueryUrl()+'sort=id"><img src="http://www.dasregistry.org/img/up_sort.gif"/></a><a href="'+this.getNewQueryUrl()+'sort=id;reverse=true"><img src="http://www.dasregistry.org/img/down_sort.gif"/></a></td>';

		// html +='<td><b>clients</b></td>';

		html += '<td><b>';
		html += 'Title';

		html += '</b><a href="'+this.getNewQueryUrl()+'sort=title"><img src="http://www.dasregistry.org/img/up_sort.gif"/></a><a href="'+this.getNewQueryUrl()+'sort=title;reverse=true"><img src="http://www.dasregistry.org/img/down_sort.gif"/></a></td>';
		html += '<td><b>Status</b><a href="'+this.getNewQueryUrl()+'sort=status"><img src="http://www.dasregistry.org/img/up_sort.gif"/></a><a href="'+this.getNewQueryUrl()+'sort=status;reverse=true"><img src="http://www.dasregistry.org/img/down_sort.gif"/></a></td>';

		// html +='<td><b>';
		// html += 'status';
		// html +='</b></td>';

		html += '<td><b>';
		html += 'Description';
		html += '</b><a href="'+this.getNewQueryUrl()+'sort=description"><img src="http://www.dasregistry.org/img/up_sort.gif"/></a><a href="'+this.getNewQueryUrl()+'sort=description;reverse=true"><img src="http://www.dasregistry.org/img/down_sort.gif"/></a></td>';
		var checked = '';
		if (showNumberOfCaps == caps.length) {
			checked = 'checked=\"no\"';
		}
		html += '<td colspan=\''
				+ showNumberOfCaps
				+ '\'><b>Capabilities<b><a href="'+this.getNewQueryUrl()+'sort=validcapabilities"><img src="http://www.dasregistry.org/img/up_sort.gif"/></a><a href="'+this.getNewQueryUrl()+'sort=validcapabilities;reverse=true"><img src="http://www.dasregistry.org/img/down_sort.gif"/></a>';
		html += '<input type=\"checkbox\" id=\"showAllCaps\" name=\"showAllCaps\" '
				+ checked + ' />show all caps</td>';

		html += '<td><b>Types';
		html += '</b></td>';

		html += '<td>Specification</td>';
		html += '<td>Project</td>';
		html += '<td>Coordinate System<a href="'+this.getNewQueryUrl()+'sort=coordinatesystem"><img src="http://www.dasregistry.org/img/up_sort.gif"/></a><a href="'+this.getNewQueryUrl()+'sort=coordinatesystem;reverse=true"><img src="http://www.dasregistry.org/img/down_sort.gif"/></a></td>';
		html += '</tr>';
		return html;
	}

	function writeSource(source, pos) {
		// alert("in writeSource");
		var text = "";
		var coordinates = source.version[0].coordinates;
		var rowspan = 1;
		if (coordinates) {
			var numberOfCoords = coordinates.length;
			// alert('number of coords'+ numberOfCoords);

			if (numberOfCoords) {
				rowspan = numberOfCoords;
			}
		}
		var propMap = createPropertyMap(source.version[0].prop);

		var daysInactive = 0;
		if (propMap['inactive']) {
			daysInactive = propMap['inactive'];
			// alert(daysBeforeDeletion);
		}
		for ( var l = 0; l < rowspan; l++) {
			if(daysInactive!=0){
				row="invalid";
			}else if (pos % 2 == 0) {
				row = 'row1';
			} else {
				row = 'row0';
			}
			var rowClassText = '<tr class=\"' + row + '\">';

			if (l == 0) {// only do this loop once for a
				// source
				// alert('in l=1');
				text += rowClassText;
				text += '<td rowspan=\'' + rowspan + '\'>' + pos + '</td>';
				text += '<td rowspan=\'' + rowspan + '\'>' + source.uri;

				text += '<div id=\"dassourceactions\" title=\"show details\"><a href=\'showdetails.jsp?auto_id='
						+ source.uri + '\'>';
				text += '<img src=\"http://www.dasregistry.org/img/messagebox_info16x16.png\" border=\"0\"/></a></div>';
				text += '<div id=\"dassourceactions\" title=\"validate\"><a href=\'validateServer.jsp?auto_id='
						+ source.uri + '\'>';
				text += '<img src=\"http://www.dasregistry.org/img/ok16x16.png\" border=\"0\"/></a></div>';

				text += '<div id=\"dassourceactions\" title=\"send to freind\"><a href=\'sendToFriend.jsp?auto_id='
						+ source.uri + '\'>';
				text += '<img src=\"http://www.dasregistry.org/img/mail_post_to16x16.png\" border=\"0\"/></a></div>';

				text += '</td><td rowspan=\'' + rowspan + '\'>' + source.title
						+ '</td>' + '<td rowspan=\'' + rowspan + '\'>';
				if (daysInactive != 0) {
					text += '<a href=\"http://www.dasregistry.org/validateServer.jsp?auto_id='
							+ source.uri
							+ '\" title=\''
							+ daysInactive
							+ ' days inactive\'><img src=\"http://www.dasregistry.org/img/messagebox_warning.png\"/>down for '
							+ daysInactive + ' days.</a></td>';
				}
				text += '</td>' + '<td rowspan=\'' + rowspan + '\'>'
						+ '<a class=\"clickDescription\"  >Show/Hide</a>'
						+ '<div class=\'shortdescription\'>' + '<a href=\"'
						+ source.doc_href + '\">Further Information</a> '
						+ source.description;
				// + res.SOURCE[i].description.substring(0,60)+'...';
				+'</div></td>';

				// alert(pos);
				var shortQueryUri = sourceUtils.getOriginalDataSourceUri(source.version[0].capability);
				// alert('shortQueryUri='+shortQueryUri);

				for (k = 0; k < showNumberOfCaps; k++) {
					text += '<td rowspan=\'' + rowspan
							+ '\' class=\'noBorder\'>';
					var cap = caps[k];
					// text+=cap;
					var image = '<img class="valid" src=\"' + 'http://www.dasregistry.org/img/clear16.gif'
							+ '\">';// default
					// color
					// for
					// img

					var status = propMap[cap];
					var img = '';

					if ('valid' == status)
						img = 'http://www.dasregistry.org/img/green16.gif';
					if ('probably_valid' == status)
						img = 'http://www.dasregistry.org/img/amber16.gif';
					if ('invalid' == status)
						img = 'http://www.dasregistry.org/img/red16.gif';
					if (img == '')
						img = 'http://www.dasregistry.org/img/clear16.gif';

					var test_range = '';
					if (coordinates) {
						if (coordinates.length > 0) {
							test_range += coordinates[0].testRange;
						}
					}

					// chop off the command from the quer_uri oin future will
					// need to get the specific uri as these will be allowed to
					// be different

					// alert(shortQueryUri);
					// var shortQueryUri=query_uri.replace(cap, "");
					// if((i==0)&&(k==0)){
					// alert(query_uri);
					// alert(shortQueryUri);
					// }
					text += '<a title=\'' + cap + ' capability is ' + status
							+ '\' href=\"'
							+ getTestUrl(shortQueryUri, cap, test_range)
							+ '\">';
					image = '<img class="valid" src=\"' + img + '\"><\/>';

					text += image + '</td>';

				}

				text += '<td rowspan=\'' + rowspan + '\'>';

				var idForTypes = 'no types';
				if (propMap['types'] == 'valid') {
					idForTypes = source.version[0].uri;// ideally should be
					// just source uri
					// =auto_id but because
					// of mirrored sources
					// need url
					text += '<a class=\"click\"  >Show/Hide Types</a>';
				}
				text += '<div class=\"ajaxTypes\" id=\"' + idForTypes
						+ '\"></div>';
				text += '</td>';// <a
				// class="click">Expand/Contract</a>
				// <div class="ajaxTypes" id="<%=auto_id
				// %>"></div>
				text += '<td rowspan=\'' + rowspan + '\'>' + propMap['spec']
						+ '</td>';
				var projectIcon = propMap['projectIcon'];
				if (projectIcon != undefined) {
					var projectId = projectIcon.substring(projectIcon
							.indexOf('=') + 1);

					text += '<td rowspan=\''
							+ rowspan
							+ '\'><a href=\'http://www.dasregistry.org/showProjectDetails.jsp?project_id='
							+ projectId + '\'\'>' + '<img src=\'' + projectIcon
							+ '\'></a></td>';
				} else {
					text += '<td rowspan=\'' + rowspan + '\'></td>';
				}
			}// end of l==0 loop for listing source once as
			// span should take care of filling in the rows
			// below.
			// alert('coordinates length='+coordinates.length);
			var padding = '<td >' + '</td>' + '<td >' + '</td>' + '<td >'

			+ '</td>' + '<td >'

			+ '</td>' + '<td >'

			+ '</td>';
			if (coordinates == undefined || coordinates == null) {
				text += padding;
			} else {
				if (coordinates[l] === undefined) {
					text += padding;
				} else {
					text += '<td >' + '<a href=\'' + coordinates[l].uri + '\'>'
							+ coordinates[l].content + '</a>'
							+ '<br/><a href=\''
							+ ''+getNewQueryUrl()+'coordinateid='
							+ getCoordinateUri(coordinates[l].uri) + '\'>'
							+ ' List Sources' + '</a>' + '</td>';
				}

			}

			text += '</tr>';
		}
		return rowClassText + text;
	}

	function writeRows(sources) {
		var start=1;
		var end=sources.source.length;
		var total=sources.source.length;
		if(sources.start!=undefined){
			//alert("undefined");
			start=sources.start;
			end=sources.end;//if no rows then assume total is the length as start stop total are not specified if no rows params
			total=sources.total;
		}
		var rowsText = "";
		var navText = start + " - " + end + " of "
				+ total + "<br/>";
			for ( var i = 0; i < sources.source.length; i++) {
			var source = sources.source[i];
			var newText = writeSource(source, start+i);
			rowsText += newText;
		}
		return rowsText;
	}

	function writeNavigationText(sources) {
		var start=sources.start;
		var end=sources.end;
		var difference=end-start+1;
		if(sources.start==undefined){
			//alert("undefined");
			start=1;
			end=sources.source.length;//if no rows then assume total is the length as start stop total are not specified if no rows params
			var navText = start + " - " + end + " of "
			+ sources.source.length+"<br/>";
			return navText;
		}
		//alert(itemsPerPage);		
		var query=this.getQueryFromFullPath();
		//alert("q in writenav="+query);
		//replace the rows param with new ones for left and right but keep the rest of the query the same
		var rowsAndQuery=query.substring(query.indexOf("rows=")+5, query.length);
		var endOfRows=rowsAndQuery.length;//if no ; then we assume the rows is the only query param
		if(rowsAndQuery.indexOf(";")>0){
			endOfRows=rowsAndQuery.indexOf(";");
		}
		var startnstop=rowsAndQuery.substring(0, endOfRows);
		//alert("start n stop="+startnstop);
		var leftNavStart=start-difference;
		var leftNavEnd=end-difference;
		var leftNavString=leftNavStart+"-"+leftNavEnd;
		var rightNavStart=start+difference;
		var rightNavEnd=end+difference;
		var rightNavString=rightNavStart+"-"+rightNavEnd;
		//alert("returnUrl in nav="+this.returnUrl);
		var leftNav="<a href=\'"+window.location.href.replace(startnstop, leftNavString)+"\'><<"+"</a> ";
		if(leftNavStart<1)leftNav="";
		var rightNav="<a href=\'"+window.location.href.replace(startnstop, rightNavString)+"\'>>>"+"</a> ";
		if(rightNavEnd>sources.total)rightNav="";
		var navText = leftNav+start + " - " + end + " of "
				+ sources.total + rightNav+"<br/>";

		return navText;
	}

	function writeTableEnd() {
		var tableEnd = '</table></div>';
		return tableEnd;
	}

	function getSourcesTable(sources) {

		this.html +=this.tableHeadHtml()
				+ this.writeRows(sources) + this.writeTableEnd();
		$("#ajaxLoaderSources").html('');
		return this.html;
	}

	function getRegistryUrlFromPath() {
		// get the query and add it to the registry root url so we get the
		// request right
		var pathAndQuery = window.location.href;
		//alert("return url="+this.returnUrl+" registrySourcesUrl="+this.registrySourcesUrl);
		
		//alert("pandquery="+pathAndQuery);
		var url = pathAndQuery.replace(this.returnUrl, this.registrySourcesUrl);
		//alert("regurl="+url);
		
		return url;
	}
	
	function getQueryFromFullPath() {
		// get the query and add it to the registry root url so we get the
		// request right
		var pathAndQuery = window.location.href;
		// alert(this.path);
		var query =  pathAndQuery.substring(pathAndQuery.indexOf("?"), pathAndQuery.length);
		return query;
	}

	function createPropertyMap(properties) {
		var map = new Object();
		if (properties.length > 0 && properties != null
				&& properties != undefined) {
			for ( var propIndex = 0; propIndex < properties.length; propIndex++) {
				var name = properties[propIndex].name;
				var value = properties[propIndex].value;
				map[name] = value;
				// alert(name +'='+value);
			}
		}
		return map;
	}
	/* Get the root url of a das source from a query uri
	 * 
	 */
	function getRootURL(queryURI) {
		// alert("calling getRootURL");
		// if(queryURI.indexOf("sources")>1){
		// return queryURI;
		// }
		var indexOfLastSlash = queryURI.lastIndexOf("/");
		var rootURL = queryURI.substring(0, indexOfLastSlash);
		var found = 0;
		// if queryuri doesn't contain a command just return the queryuri
		for ( var i = 0; i < caps.length; i++) {
			// alert(rootURL.indexOf(caps[i]));
			if (queryURI.indexOf(caps[i]) > 0) {
				found = 1;
			}

		}
		// if no command found just return the uri don't chop it
		if (found == 0) {
			return queryURI;
		}
		// alert('rootUrl='+rootURL);
		return rootURL;
	}

	function getCoordinateUri(coordinateUri) {
		var lastSlash = coordinateUri.lastIndexOf("/");
		var uri = coordinateUri.substring(lastSlash + 1, coordinateUri.length);
		return uri;
	}

	function getTestUrl(baseuri, command, testCode) {
		var testurl;
		var extension;
		// alert(baseuri+' ' +command+' '+testCode);
		// should change this to get the test url from the
		// das/sources/dsn/capabilities uri?? will this confuse clients?
		if (command == "sources") {
			extension = "sources";
		}

		if (command == "stylesheet") {
			extension = command;
		}

		if (command == "features") {
			extension = command + "?segment=" + testCode;
		}

		if (command == "types") {
			extension = command;
		}

		if (command == "sequence") {
			extension = command + "?segment=" + testCode;
		}

		if (command == "entry_points") {
			extension = command;
		}

		if (command == "alignment") {
			extension = command + "?query=" + testCode;
		}

		if (command == "structure") {
			extension = command + "?query=" + testCode;
		}

		if (command == "interaction") {
			extension = command + "?interactor=" + testCode;
		}

		if (command == "unknown-segment") {
			extension = "features" + "?segment=" + 'invalidTestCode'
					+ ":1,1000";
		}

		if (command == "unknown-feature") {
			extension = "features" + "?feature_id=" + 'invalidTestCode';
		}

		if (command == "error-segment") {
			extension = "features" + "?segment=" + 'invalidTestCode'
					+ ":1,1000";
		}

		if (command == "maxbins") {
			extension = "features" + "?segment=" + testCode + ";maxbins=1";
		}
		if (command == "feature-by-id") {
			extension = "features" + "?feature_id=";
		}
		if (command == "bigfile-bam") {
			extension == "";
			return baseuri;
		}

		testurl = baseuri + '\/' + extension;

		return testurl;
	}
	
	

	
}